package adventure.vocation;

import adventure.commands.skills.Skill;
import adventure.commands.skills.SkillEdit;
import colour.ColourUtil;
import java.util.ArrayList;
import java.util.Random;
import player.Player;

/**
 *
 * @author Michael Hanns
 *
 */
public class VocationImp implements Vocation, VocationEdit, Cloneable {

    // ID, name and description
    private int id;
    private String name;
    private String description;
    //
    // Base stats
    private int baseAtk;
    private int baseDef;
    private int baseInt;
    private int baseSpd;
    private int baseLck;
    //
    // Chance to increase stats
    private double chanceIncAtk;
    private double chanceIncDef;
    private double chanceIncInt;
    private double chanceIncSpd;
    private double chanceIncLck;
    //
    // Skillls learned
    private ArrayList<Skill> skills;

    public VocationImp(int id) {
        this.id = id;
        this.name = "";
        this.description = "";

        this.baseAtk = 10;
        this.baseDef = 10;
        this.baseInt = 10;
        this.baseSpd = 10;
        this.baseLck = 10;

        this.chanceIncAtk = 0.5;
        this.chanceIncDef = 0.5;
        this.chanceIncInt = 0.5;
        this.chanceIncSpd = 0.5;
        this.chanceIncLck = 0.5;

        this.skills = new ArrayList<Skill>();
    }
    
    @Override
    public void setID(int id) {
        this.id = id;
    }

    @Override
    public void setName(String name) {
        this.name = name;
    }

    @Override
    public void setDescription(String desc) {
        this.description = desc;
    }

    @Override
    public void setBaseAttack(int val) {
        this.baseAtk = val;
    }

    @Override
    public void setBaseDefence(int val) {
        this.baseDef = val;
    }

    @Override
    public void setBaseIntel(int val) {
        this.baseInt = val;
    }

    @Override
    public void setBaseSpeed(int val) {
        this.baseSpd = val;
    }

    @Override
    public void setBaseLuck(int val) {
        this.baseLck = val;
    }

    @Override
    public void setChanceIncAttack(double val) {
        this.chanceIncAtk = val;
    }

    @Override
    public void setChanceIncDefence(double val) {
        this.chanceIncDef = val;
    }

    @Override
    public void setChanceIncIntel(double val) {
        this.chanceIncInt = val;
    }

    @Override
    public void setChanceIncSpeed(double val) {
        this.chanceIncSpd = val;
    }

    @Override
    public void setChanceIncLuck(double val) {
        this.chanceIncLck = val;
    }

    @Override
    public int getID() {
        return id;
    }

    @Override
    public String getName() {
        return name;
    }

    @Override
    public String getDescription() {
        return description;
    }

    @Override
    public int getBaseAttack() {
        return baseAtk;
    }

    @Override
    public int getBaseDefence() {
        return baseDef;
    }

    @Override
    public int getBaseIntel() {
        return baseInt;
    }

    @Override
    public int getBaseSpeed() {
        return baseSpd;
    }

    @Override
    public int getBaseLuck() {
        return baseLck;
    }

    @Override
    public double getChanceAttack() {
        return chanceIncAtk;
    }

    @Override
    public double getChanceDefence() {
        return chanceIncDef;
    }

    @Override
    public double getChanceIntel() {
        return chanceIncInt;
    }

    @Override
    public double getChanceSpeed() {
        return chanceIncSpd;
    }

    @Override
    public double getChanceLuck() {
        return chanceIncLck;
    }

    @Override
    public boolean incAttack() {
        Random r = new Random();
        if (r.nextDouble() < chanceIncAtk) {
            return true;
        }
        return false;
    }

    @Override
    public boolean incDefence() {
        Random r = new Random();
        if (r.nextDouble() < chanceIncDef) {
            return true;
        }
        return false;
    }

    @Override
    public boolean incIntelligence() {
        Random r = new Random();
        if (r.nextDouble() < chanceIncInt) {
            return true;
        }
        return false;
    }

    @Override
    public boolean incSpeed() {
        Random r = new Random();
        if (r.nextDouble() < chanceIncSpd) {
            return true;
        }
        return false;
    }

    @Override
    public boolean incLuck() {
        Random r = new Random();
        if (r.nextDouble() < chanceIncLck) {
            return true;
        }
        return false;
    }

    @Override
    public boolean knowsSkill(int skillNo, int playerLvl) {
        for (int c = 0; c < skills.size(); c++) {
            if (((SkillEdit) skills.get(c)).getID() == skillNo
                    && ((SkillEdit) skills.get(c)).levelLearned() <= playerLvl) {
                return true;
            }
        }
        return false;
    }

    @Override
    public boolean knowsSkill(int playerLvl, String command, boolean admin) {
        for (int c = 0; c < skills.size(); c++) {
            if (((SkillEdit) skills.get(c)).levelLearned() <= playerLvl
                    && skills.get(c).isCommand(command)) {
                return true;
            }
        }
        return false;
    }

    /*
     * @output - Returns true if skill learned, false if they already know it
     */
    @Override
    public boolean learnSkill(Skill skill) {
        for (int c = 0; c < skills.size(); c++) {
            if (((SkillEdit) skills.get(c)).getID() == ((SkillEdit) skill).getID()) {
                return false;
            }
        }
        skills.add(skill);
        return true;
    }

    @Override
    public void forgetSkill(int skillID) {
        for (int x = 0; x < skills.size(); x++) {
            if (skills.get(x).getID() == skillID) {
                skills.remove(x);
            }
        }
    }

    @Override
    public boolean removeSkill(int skillPos) {
        if (skillPos < 0 || skillPos >= skills.size()) {
            return false;
        } else {
            skills.remove(skillPos);
            return true;
        }
    }

    @Override
    public String performSkill(Player player, String[] commandArgs) {
        for (int c = 0; c < skills.size(); c++) {
            if (((SkillEdit) skills.get(c)).levelLearned() <= player.getLevel()
                    && skills.get(c).isCommand(commandArgs[0])) {
                return skills.get(c).validateAndExecute(player, commandArgs);
            }
        }
        return "";
    }

    @Override
    public String newSkillsLearned(int level) {
        String output = "";
        for (int c = 0; c < skills.size(); c++) {
            if (((SkillEdit) skills.get(c)).levelLearned() == level) {
                output += "\nYou have learned " + ((SkillEdit) skills.get(c)).getName();
            }
        }
        return output;
    }

    @Override
    public String[] getSkillsKnown(int level) {
        ArrayList<String> skillsKnown = new ArrayList<String>();
        for (int c = 0; c < skills.size(); c++) {
            if (((SkillEdit) skills.get(c)).levelLearned() <= level) {
                skillsKnown.add(ColourUtil.colourise(((SkillEdit) skills.get(c)).getName(),
                        skills.get(c).getTypeColour()));
            }
        }
        String[] out = new String[skillsKnown.size()];
        return skillsKnown.toArray(out);
    }

    @Override
    public String getSkillInfo(String skillName) {
        for (int c = 0; c < skills.size(); c++) {
            System.out.println(skillName.toUpperCase() + " ... " + ((SkillEdit) skills.get(c)).getName().toUpperCase());
            if (((SkillEdit) skills.get(c)).getName().toUpperCase().startsWith(skillName.toUpperCase())) {
                return skills.get(c).getSkillHelp();
            }
        }

        return "You do not know how to " + skillName + "!";
    }

    @Override
    public Skill[] getSkills() {
        Skill[] skillsOut = new Skill[skills.size()];

        return skills.toArray(skillsOut);
    }

    @Override
    public Vocation cloneThis() {
        Vocation newClone = new VocationImp(0);
        try {
            newClone = (Vocation) this.clone();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return newClone;
    }

    @Override
    public Object clone() {
        try {
            Object clone = super.clone();
            ((VocationImp) clone).skills = new ArrayList<Skill>();

            for (int c = 0; c < skills.size(); c++) {
                ((VocationImp) clone).skills.add(((SkillEdit) skills.get(c)).cloneThis());
            }

            return clone;
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return null;
    }
}
